package test.com.sms.webservice.base;

import java.io.StringReader;

import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.Assert;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.w3c.dom.Document;

import test.com.sms.framework.TestAbstract;
import test.com.sms.webservice.wfm.FindAvailableFEsAndSubsWSTest;

import com.sms.common.util.FileUtil;
import com.sms.common.util.XMLUtil;

public abstract class SmsWebServiceTestAbstract extends TestAbstract 
{
	
	/**
	 * The following system properties can be passed to UT at the startup:
	 * -Dprotocol -Dhost -Dport -Droot.url
	 */
	public static String TEST_URL = 
			System.getProperty("sms.protocol", "http").trim() + "://" + 
			System.getProperty("sms.host", "localhost").trim() + ":" + 
			System.getProperty("sms.port", "8080").trim() + "/" + 
			System.getProperty("sms.root.url", "SMS-Web-App").trim();
	
	
	protected static final String AUTH_URI = TEST_URL;
	protected static final String VALID_USER_ID = "smstest";
	protected static final String INVALID_USER_ID = "smstest1";
	protected static final String VALID_PASSWORD = "123456";

	protected String authenticate(String id, String password, String resultFlag, String sessionId)
	{
		RestTemplate restTemplate = new RestTemplate();
		return authenticate(restTemplate,  id,  password,  resultFlag, sessionId);
	}
	
	protected String authenticate(RestTemplate restTemplate, String id, String password, String resultFlag, String sessionId)
	{
		MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
		map.add("username", id);
		map.add("password", password);
		if (sessionId != null)
		{
			map.add("JSESSIONID", sessionId);
		}
		String result =  restTemplate.postForObject(AUTH_URI, map, String.class);
		return result;
	}

	protected String logout(String sessionId)
	{
		RestTemplate restTemplate = new RestTemplate();
		MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
		map.add("logout", "true");
		if (sessionId != null)
		{
			map.add("JSESSIONID", sessionId);
		}
		String result =  restTemplate.postForObject(AUTH_URI, map, String.class);
		return result;
	}

	protected String getSessionId (String authenticationResultXml)
	{
		int pos1 = authenticationResultXml.indexOf("<sessionid>") + 11;
		int pos2 = authenticationResultXml.indexOf("</sessionid>");
		String sessionId = authenticationResultXml.substring(pos1, pos2);
		return sessionId;

	}


	protected void executeWebService (String url, String inputXMLFile, String inputXSDFile, String outputXSDFile, Class testClass) throws Exception
	{
		executeWebService ( url,  inputXMLFile,  inputXSDFile,  outputXSDFile,  testClass, false, false);
	}

	
	protected void executeWebService (String url, String inputXMLFile, String inputXSDFile, String outputXSDFile, Class testClass, 
			boolean expectErrors, boolean expectAlerts) throws Exception
	{
	
		// Validate input xml with XSD
		String inputXML= FileUtils.readFileToString(FileUtil.getFile(inputXMLFile, FindAvailableFEsAndSubsWSTest.class ));
		validateAgainstSchema(inputXML, inputXSDFile, testClass);
		
		// Get responseXML from web service
		String responseXML = executeWebService(url, inputXML);
	
		// Validate responseXML with XSD
		validateAgainstSchema(responseXML,outputXSDFile , testClass);
		
		// Make sure there are no errors and alerts
		checkErrorsAndAlerts(responseXML, expectErrors, expectAlerts);
	}
	
	protected String executeWebService(String url, String inputXML)
	{
		RestTemplate restTemplate = new RestTemplate();
		String resultXML = restTemplate.postForObject((TEST_URL + url), inputXML, String.class);
		return resultXML;
	}
	
	
	
	private String executeWebServiceWithParameters (String url, String inputXML)
	{
		RestTemplate restTemplate = new RestTemplate();
		MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
		map.add("inputXML", inputXML);
		return  restTemplate.postForObject(url, inputXML, String.class);
	}


	protected void validateAgainstSchema(String xml, String xsdRelativeFilePath, Class rootClass) throws Exception
	{
		StringReader reader = new StringReader(xml);   
		SchemaFactory factory = SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");   
		Schema schema = factory.newSchema(FileUtil.getFile(xsdRelativeFilePath, rootClass ));   
		Validator val = schema.newValidator();  
		try
		{
			val.validate(new StreamSource(reader));
		}
		catch( Exception e)
		{
			System.out.println("XML failed validation. Class: " + rootClass.getCanonicalName() + " XML: " + xml);
			e.printStackTrace();
			throw e;
		}

	}
	
	protected static void checkErrorsAndAlerts(String responseXML, boolean expectErrors, boolean expectAlerts) throws Exception
	{
		try
		{
			Document document = XMLUtil.createDocumentFromXMLString(responseXML);
			if (!expectErrors)
				Assert.assertEquals("Testing errors xpath", "",  XMLUtil.getValueByXPath(document, "//errors"));
			else
				Assert.assertTrue("Testing  errors xpath", StringUtils.isNotBlank(XMLUtil.getValueByXPath(document, "//errors")));
			
			if (!expectAlerts)
				Assert.assertEquals("Testing alerts xpath", "",  XMLUtil.getValueByXPath(document, "//alerts"));
			else
				Assert.assertTrue("Testing alerts xpath", StringUtils.isNotBlank(XMLUtil.getValueByXPath(document, "//errors")));
		}
		catch (Throwable t)
		{
			Assert.assertTrue(t.getMessage(), responseXML.indexOf("<errors/>") >= 0);
			Assert.assertTrue(t.getMessage(), responseXML.indexOf("<alerts/>") >= 0);
		}

	}

}
